package com.wsoft.bpm.listener.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wsoft.bpm.bean.OptionalPersonnelVariableValue;
import com.wsoft.bpm.component.command.GetProcessCmd;
import com.wsoft.bpm.component.sign.DynamicUserTaskComponent;
import com.wsoft.bpm.entity.ActWorkflowConfigEntity;
import com.wsoft.bpm.enums.DynamicApprovalType;
import com.wsoft.bpm.enums.ExecuteType;
import com.wsoft.bpm.mapper.BpmActivitiMapper;
import com.wsoft.bpm.query.node.TaskQuery;
import com.wsoft.bpm.service.IActWorkflowConfigService;
import com.wsoft.bpm.utils.ActivityUtils;
import com.wsoft.core.exception.Asserts;
import com.wsoft.core.service.CommonMemberService;
import com.wsoft.core.service.CommonOrgService;
import com.wsoft.core.vo.MemberVO;
import com.wsoft.core.vo.OrganizationVO;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.delegate.TaskListener;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.activiti.engine.impl.el.ExpressionManager;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 用户节点自选人员监听器
 *
 * @author zhonglj
 * @date 2024-11-01 11:07
 **/
//@Component("dynamicUserTaskListener")
public class DynamicUserTaskListener implements TaskListener {
    @Resource
    private RuntimeService runtimeService;
    @Resource
    private ManagementService managementService;
    @Resource
    private TaskService taskService;
    @Resource
    private IActWorkflowConfigService workflowConfigService;
    @Resource
    private BpmActivitiMapper bpmActivitiMapper;
    @Resource
    private ProcessEngine processEngine;
    @Resource
    private HistoryService historyService;

    @Override
    public void notify(DelegateTask delegateTask) {
        ActWorkflowConfigEntity config = workflowConfigService.getOne(
                Wrappers.lambdaQuery(ActWorkflowConfigEntity.class)
                        .eq(ActWorkflowConfigEntity::getProcDefId, delegateTask.getProcessDefinitionId())
                        .eq(ActWorkflowConfigEntity::getActId, delegateTask.getTaskDefinitionKey())
        );
        if (config != null && StrUtil.isNotBlank(config.getJson())) {
            TaskQuery taskQuery = JSONUtil.toBean(config.getJson(), TaskQuery.class);
            String dynamicApprovalType = taskQuery.getDynamicApprovalType();
            String dynamicApprovalValue = taskQuery.getDynamicApprovalValue();
            if (StrUtil.equals(dynamicApprovalType, DynamicApprovalType.OPTIONAL_PERSONNEL.getValue())) {
                optionalPerson(delegateTask);

            } else {
                dynamicPerson(delegateTask, dynamicApprovalType, dynamicApprovalValue);
            }
        }

    }

    @Resource
    private CommonMemberService commonMemberService;
    @Resource
    private CommonOrgService commonOrgService;


    private void dynamicPerson(DelegateTask delegateTask, String dynamicApprovalType, String dynamicApprovalValue) {
        if (StrUtil.equals(dynamicApprovalType, DynamicApprovalType.DEPARTMENT_HEAD.getValue())) {
            // 部门负责人
            OrganizationVO orgInfo = commonOrgService.getOrgInfo(Long.valueOf(dynamicApprovalValue));
            Long orgLeaderId = orgInfo.getMemberId();
            if (orgLeaderId != null) {
                taskService.setAssignee(delegateTask.getId(), orgLeaderId.toString());
            }

        } else {
            // 上一个用户节点审批人
            Process process = managementService.executeCommand(new GetProcessCmd(delegateTask.getProcessDefinitionId()));
            FlowElement flowElement = process.getFlowElement(delegateTask.getTaskDefinitionKey());
            List<FlowElement> preFirstUserTask = ActivityUtils.getPreFirstUserTask(flowElement);
            if (CollUtil.isEmpty(preFirstUserTask)) {
                Asserts.fail("[bpm.dynamic.preUser.empty]");
            }
            String taskDefKey = preFirstUserTask.get(0).getId();
            // 获取上一个节点的审批历史
            List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                    .processInstanceId(delegateTask.getProcessInstanceId())
                    .taskDefinitionKey(taskDefKey)
                    .orderByTaskCreateTime()
                    .desc()
                    .list();
            if (CollUtil.isEmpty(list)) {
                Asserts.fail("[bpm.dynamic.preTask.empty]");
            }
            HistoricTaskInstance lastTask = list.get(0);
            // 上一节点审批人
            String lastAssign = lastTask.getAssignee();

            if (StrUtil.equals(dynamicApprovalType, DynamicApprovalType.ASSIGNED_SUPERVISOR.getValue())) {
                int countDown = Integer.valueOf(dynamicApprovalValue);
                Long targetLeaderId = null;
                while (countDown > 0) {
                    MemberVO memberInfo = commonMemberService.getMemberInfo(Long.valueOf(lastAssign));
                    Long leaderId = memberInfo.getMemberLeaderId();
                    if (leaderId != null) {
                        targetLeaderId = leaderId;
                    } else {
                        // 倒计时未结束，先找到了为空的领导id,循环无法继续
                        break;
                    }
                    // 倒计时-1
                    countDown--;

                }

                if (targetLeaderId != null) {
                    // 设置审批人
                    taskService.setAssignee(delegateTask.getId(), targetLeaderId.toString());
                }

            } else if (StrUtil.equals(dynamicApprovalType, DynamicApprovalType.CONTINUOUS_SUPERIOR.getValue())) {
                int countDown = Integer.valueOf(dynamicApprovalValue);
                List<String> targetLeaderIdList = new ArrayList<>();
                while (countDown > 0) {
                    MemberVO memberInfo = commonMemberService.getMemberInfo(Long.valueOf(lastAssign));
                    Long leaderId = memberInfo.getMemberLeaderId();
                    if (leaderId != null) {
                        targetLeaderIdList.add(leaderId.toString());
                    } else {
                        // 倒计时未结束，先找到了为空的领导id,循环无法继续
                        break;
                    }
                    // 倒计时-1
                    countDown--;

                }

                if (CollUtil.isNotEmpty(targetLeaderIdList)) {
                    // 后续节点拼接一个动态顺序审批链
                    if (CollUtil.isNotEmpty(targetLeaderIdList)) {
                        DynamicUserTaskComponent dynamicUserTaskComponent = new DynamicUserTaskComponent();
                        String firstNodeId = lastTask.getTaskDefinitionKey();
                        // 获取下一个节点
                        FlowElement nextNode = getNextNode(delegateTask.getExecution(), delegateTask.getProcessDefinitionId(), delegateTask.getTaskDefinitionKey());
                        String lastNodeId = nextNode.getId();
                        dynamicUserTaskComponent.addDynamicUserTaskByStr(delegateTask.getProcessDefinitionId(),
                                delegateTask.getProcessInstanceId(), processEngine, targetLeaderIdList, firstNodeId, lastNodeId, delegateTask.getId(), delegateTask.getTaskDefinitionKey());
                    }
                }

            }
        }

    }

    private FlowElement getNextNode(DelegateExecution execution, String processDefinitionId, String currentActivityId) {
        // 获取流程
        Process process = managementService.executeCommand(new GetProcessCmd(processDefinitionId));
        // 创建表达式
        ProcessEngineConfigurationImpl config = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration();
        ExpressionManager expressionManager = config.getExpressionManager();

        if (process != null) {
            // 获取当前节点
            FlowElement currentFlowElement = process.getFlowElement(currentActivityId);

            if (currentFlowElement != null) {
                // 获取下一个节点
                List<SequenceFlow> outgoingFlows = ((FlowNode) currentFlowElement).getOutgoingFlows();

                if (!outgoingFlows.isEmpty()) {
                    for (SequenceFlow out : outgoingFlows) {
                        String conditionExpression = out.getConditionExpression();
                        if (conditionExpression == null) {
                            // 没有条件视为通过
                            return process.getFlowElement(out.getTargetRef());
                        }

                        Expression expression = expressionManager.createExpression(conditionExpression);
                        Object value = expression.getValue(execution);
                        boolean pass = ObjectUtil.equal(value, true);
                        if (pass) {
                            // 通过流程条件判断
                            return process.getFlowElement(out.getTargetRef());
                        }
                    }
                }
            }
        }

        return null;
    }

    private void optionalPerson(DelegateTask delegateTask) {
        String variableName = DynamicApprovalType.OPTIONAL_PERSONNEL.getValue();
        Object object = runtimeService.getVariable(delegateTask.getExecutionId(), variableName);
        if (object == null) {
            Asserts.fail("[bpm.optionalPerson.empty]");
        }
        List<OptionalPersonnelVariableValue> values = (List<OptionalPersonnelVariableValue>) object;
        if (CollUtil.isEmpty(values)) {
            Asserts.fail("[bpm.optionalPerson.empty]");
        }

        OptionalPersonnelVariableValue variableValue = null;
        if (CollUtil.size(values) == 1) {
            variableValue = values.get(0);

        } else {
            // 根据前置用户任务获取
            Process process = managementService.executeCommand(new GetProcessCmd(delegateTask.getProcessDefinitionId()));
            FlowElement flowElement = process.getFlowElement(delegateTask.getTaskDefinitionKey());
            List<FlowElement> preFirstUserTask = ActivityUtils.getPreFirstUserTask(flowElement);
            if (CollUtil.isEmpty(preFirstUserTask)) {
                Asserts.fail("[bpm.dynamic.preUser.empty]");
            }

            List<String> preTaskDefKeys = preFirstUserTask.stream().map(BaseElement::getId).collect(Collectors.toList());
            values = values.stream().filter(e -> CollUtil.contains(preTaskDefKeys, e.getTaskDefKey())).collect(Collectors.toList());
            if (CollUtil.size(values) == 0) {
                Asserts.fail("[bpm.optionalPerson.config.empty]");
            }
            if (CollUtil.size(values) > 1) {
                Asserts.fail("[bpm.optionalPerson.config.over]");
            }

            variableValue = values.get(0);
        }

        String executeType = variableValue.getExecuteType();
        Object executeExpression = variableValue.getExecuteExpression();
        if (StrUtil.isNotBlank(executeType) && executeExpression != null) {
            // 后续任务设置为指定审批人
            String currentTaskId = delegateTask.getId();
            // 动态添加用户自选审批人
            if (ExecuteType.ASSIGNEE.getValue().equals(executeType)) {
                taskService.setAssignee(currentTaskId, (String) executeExpression);

            } else if (ExecuteType.CANDIDATE_USER.getValue().equals(executeType)) {
                List<String> candidateUsers = (List<String>) executeExpression;
                candidateUsers.stream()
                        .forEach(user -> taskService.addCandidateUser(currentTaskId, user));

            } else if (ExecuteType.CANDIDATE_ORG.getValue().equals(executeType)
                    || ExecuteType.CANDIDATE_ROLE.getValue().equals(executeType)
                    || ExecuteType.CANDIDATE_LEVEL.getValue().equals(executeType)
                    || ExecuteType.CANDIDATE_POSITION.getValue().equals(executeType)) {
                String candidateGroups = ExecuteType.getCandidateGroups(executeType, (List<String>) executeExpression);
                StrUtil.split(candidateGroups, ",").stream()
                        .forEach(group -> taskService.addCandidateGroup(currentTaskId, group));

            } else if (ExecuteType.EXECUTE_EXPRESSION.getValue().equals(executeType)) {
                //todo 表达式的定义和执行，例如:${parent.name like '张%'} 上级领导为张姓领导

            }
        }
    }
}
